/*
 * Ports.hpp
 *
 * Created: 7/07/2014 5:09:18 PM
 *  Author: MacGyver
 */ 


#ifndef PORTS_H_
#define PORTS_H_

#include <avr/io.h>

class PORT;
class PIN;
class PWM;

class PWM
{
	public:
		#define		SET_DUTY(x)		(255u / (100u / (x)))
		enum tenMODE
		{
			MODE_NORMAL					= 0b00000000,
			MODE_PHASE_CORRECTED		= 0b00000001,
			MODE_PHASE_FREQ_CORRECTED	= 0b00000010,
			MODE_FAST_PWM				= 0b00000011,
			MODE_MASK					= 0b00000011
		};

		enum tenPRESCALER
		{
			PSCL_STOP				= 0b00000000,
			PSCL_DIV_NONE			= 0b00000001,
			PSCL_DIV_8				= 0b00000010,
			PSCL_DIV_64				= 0b00000011,
			PSCL_DIV_256			= 0b00000100,
			PSCL_DIV_1024			= 0b00000101,
			PSCL_DIV_EXT_FALLING	= 0b00000110,
			PSCL_DIV_EXT_RISING		= 0b00000111,
			PSCL_MASK				= 0b00000111
		};
		
		enum tenINVERSION
		{
			INV_NON_INVERTED		= 0b10000000,
			INV_INVERTED			= 0b11000000,
			INV_MASK				= 0b11000000
		};		
		
	private:
		//static tenMODE mode;
		//static tenPRESCALER preScaler;
		//static tenINVERSION inverted;
		
	protected:
		volatile uint8_t *WGMx;
		volatile uint8_t *OCRx;
		volatile uint8_t *TCNTx;
		volatile uint8_t *TCCRxA;
		volatile uint8_t *TCCRxB;
	
	private:
		PIN * PINx;
		
	public:
		PWM(PIN * pin, tenMODE mode);
		PWM() {}
		~PWM() {}
	
		void vSetPreScaler( tenPRESCALER prescale );
	
		void vSetMode( tenMODE mode );
	
		void vSetDuty( uint8_t duty );
		
		void vSetInversion( tenINVERSION inverted );
		
		uint8_t u8GetCurrentCount()
		{
			return *TCNTx;
		}
};

class USART
{
	private:
		volatile uint8_t * UBRR0xL;
		volatile uint8_t * UBRR0xH;
		volatile uint8_t * UCSR0xA;
		volatile uint8_t * UCSR0xB;
		volatile uint8_t * UCSR0xC;
		volatile uint8_t * UDRx;
		
		struct  
		{
			uint8_t u8Byte;
			union
			{
				uint8_t u8RXComplete	: 1;
				uint8_t u8TXComplete	: 1;
				uint8_t u8DataRegEmpty	: 1;
				uint8_t u8FrameError	: 1;
				uint8_t u8DataOverrun	: 1;
				uint8_t u8ParityError	: 1;
				uint8_t u8DoubleTXRate	: 1;
				uint8_t u8MultiMCUMode	: 1;
			} UCSR0xA;
			
			union
			{
				uint8_t u8RXCompleteIntEn	: 1;
				uint8_t u8TXCompleteIntEn	: 1;
				uint8_t u8DataRegEmptyIntEn	: 1;
				uint8_t u8RXEn				: 1;
				uint8_t u8TXEn				: 1;
				uint8_t u8CharSize			: 1;
				uint8_t u8RXDataBit8		: 1;
				uint8_t u8TXDataBit8		: 1;
			} UCSR0xB;	
			
			union
			{
				uint8_t u8CFG_MODE			: 2;
				uint8_t u8CFG_Parity		: 2;
				uint8_t u8CFG_StopBit		: 1;
				uint8_t u8CFG_CharSize		: 3;
				uint8_t u8CFG_ClkPolarity	: 1;
			} UCSR0xC;							
		} stREG;
	
	public:
		USART()
		{
			UBRR0xL = 0xC4;
			UBRR0xH = 0xC5;
			/*Set baud rate */
			UBRR0H = (unsigned char)(ubrr>>8);
			UBRR0L = (unsigned char)ubrr;
			
			/* Enable receiver and transmitter */
			UCSR0B = (1<<RXEN0)|(1<<TXEN0);

			/* Set frame format: 8data, 2stop bit */
			UCSR0C = (1<<USBS0)|(3<<UCSZ00);			
		}
		~USART() {}
			
		void vSetBaudrate(uint32_t u32baudrate)
		{
			
		}
		
		void vSetParity()
		{
			
		}
		
		void vSetStopBits()
		{
			
		}
		
		void vTransmit()
		{
			
		}
		
		void vReadData()
		{
			
		}
};

class PIN : private PWM, USART
{
	public:
		enum tenDIRECTION
		{
			INPUT,
			OUTPUT
		};
		static tenDIRECTION DIRECTION;
		
		enum tenSTATE
		{
			OFF,
			ON
		};
		static tenSTATE STATE;
		uint8_t u8Bit;

	private:
		PORT * PORTx;			

	public:
		PIN(PORT * oPort, uint8_t pin);
		PIN() {}
		~PIN() {}
		
		void vSet();
		void vClear();
		tenSTATE enGet();
		void vSetDirection(tenDIRECTION dir);
		void vSetPullUp(tenSTATE state);	
		
	friend class PWM;		
};

class PORT
{
	public:
		static const uint8_t u8NoOfPINs = 8;
		
		PIN * PINs[u8NoOfPINs];
	
	protected:
		volatile uint8_t *DDRx;
		volatile uint8_t *PORTx;
		volatile uint8_t *PINx;
			
	public:
		PORT(volatile uint8_t * port);		
		~PORT();
		
		friend class PWM;
		friend class PIN;
};
			
#endif /* PORTS_H_ */